package com.boge.parse.ioByte;

import java.io.IOException;
import java.nio.charset.Charset;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.slf4j.LoggerFactory;

import com.boge.parse.Amf3Stream;
import com.boge.socket.ActionData;
import com.boge.socket.Context;
import com.boge.util.ZlibUtil;

import flex.messaging.io.amf.Amf3Input;

public class IoByteProtocolDecoder implements ProtocolDecoder {

	private final AttributeKey CONTEXT = new AttributeKey(getClass(), "context");  
    private final Charset charset;  
    private int maxPackLength = 100;
    /** 接收最大字节  2M */             
    private long receiveMax = 1024*1024*2;
	
    public IoByteProtocolDecoder() {  
        this(Charset.defaultCharset());
    } 
    
    public IoByteProtocolDecoder(Charset charset) {  
        this.charset = charset;  
    }
    
    public int getMaxLineLength() {  
        return maxPackLength;  
    }
    
    public void setMaxLineLength(int maxLineLength) {  
        if (maxLineLength <= 0) {  
            throw new IllegalArgumentException("maxLineLength: " + maxLineLength);  
        }  
        this.maxPackLength = maxLineLength;
    }
    
    private Context getContext(IoSession session) {  
        Context ctx;  
        ctx = (Context) session.getAttribute(CONTEXT);  
        if (ctx == null) {  
            ctx = new Context(charset);  
            session.setAttribute(CONTEXT, ctx);   
        }   
        return ctx;  
    }  
    
	@Override
	public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
			throws Exception {
//		System.out.println("decode");
		
        //先获取上次的处理上下文，其中可能有未处理完的数据  
        Context ctx = getContext(session);  
        // 先把当前buffer中的数据追加到Context的buffer当中   
        ctx.append(in);   
        
        dealDecode(session, ctx, out);
	}
	
	/**
	 * 处理数据
	 * @param session
	 * @param ctx
	 * @param out
	 * @throws IOException
	 * @throws ClassNotFoundException 
	 */
	@SuppressWarnings("rawtypes")
	private void dealDecode(IoSession session, Context ctx, ProtocolDecoderOutput out) throws IOException, ClassNotFoundException {
		final int packHeadLength = 5;
		//把position指向0位置，把limit指向原来的position位置  
        IoBuffer buf = ctx.getBuffer();
		buf.flip();
//        System.out.println("上次缓存的数据长度="+buf.remaining());
        // 然后按数据包的协议进行读取  
        while (buf.remaining() >= packHeadLength) {  
            buf.mark();  
            // 读取消息头部分
//            System.out.println("总数据长度="+buf.remaining());
            int length = buf.getInt();// 获取总数长度
            if (length >= receiveMax) {
            	LoggerFactory.getLogger(getClass()).error("dealDecode解析长度length="+length+", 大于最大"+receiveMax+", 该玩家被强制关闭");
        		session.closeNow();
				return;
			}
//            System.out.println("读取长度后的数据长度="+buf.remaining());
            //检查读取的包头是否正常，不正常的话清空buffer  
            if (length < 0) {
//	            	||length > maxPackLength
                buf.clear(); 
                break;  
            } else if (length >= packHeadLength && length <= buf.remaining()) {
            	//读取正常的消息包，并写入输出流中，以便IoHandler进行处理  
//            	System.out.println("得到的接收数据长度="+length);
//            	System.out.println("当前可用数据长度="+buf.remaining());
            	byte[] by = new byte[length];
//            	byte[] by = Arrays.copyOf(buf.array(), buf.remaining()+4);
            	buf.get(by, 0, length);
//	            System.out.println("成功复制数据后的长度="+by.length);
            	Amf3Input input = null;
            	try {
            		// 解压
            		by = ZlibUtil.decompress(by);
            		// 解密
            		by = ctx.getAes().decrypt(by);
            		length = by.length; // 重新赋值长度
            		input = Amf3Stream.newAmf3Input(by);
//              	int len = input.readInt();
//            		System.out.println("长度="+length);
//             		System.out.println("包头="+input.available());
            		if (length <= input.available()+4) {
//                		int dataLeng = input.available();
                		ActionData data = new ActionData(0);
//	                	System.out.println("事件头="+data.getAction());
//	                	System.out.println("获取了事件头后剩余的="+input.available());
//						System.out.println("获取包头后的长度,"+input.available()+", "+buf.remaining());
                		data.setVerify(input.readLong());
                		data.setAction(input.readInt());
                		int byteLen = input.readInt();// 获取长度
                		byte[] bytes = new byte[byteLen];
                		input.read(bytes, 0, byteLen);
                		data.setBuf(bytes);
//						System.out.println("获取所有数据后的长度,"+input.available()+", "+buf.remaining());
//	                	System.out.println(data.getData());
                		out.write(data);
                	}
				} catch (Exception e) {
					LoggerFactory.getLogger(getClass()).error("读取数据错误  不符合要求的数据", e);
				} finally {
					if (input != null) {
						input.close();
					}
				}
//              System.err.println("剩余"+buf.remaining()+", "+ ctx.getBuffer().remaining());
            } else {  
                // 如果消息包不完整  
                // 将指针重新移动消息头的起始位置   
                buf.reset();   
                break;  
            }
        } 
        
        if (buf.hasRemaining()) {  
            // 将数据移到buffer的最前面   
            IoBuffer temp = IoBuffer.allocate(maxPackLength).setAutoExpand(true);  
            temp.put(buf);  
            temp.flip();  
            buf.clear();  
            buf.put(temp);  
        } else {// 如果数据已经处理完毕，进行清空  
            buf.clear();   
        }  
        
	}

	@Override
	public void finishDecode(IoSession session, ProtocolDecoderOutput out)
			throws Exception {

	}

	@Override
	public void dispose(IoSession session) throws Exception {
		Context ctx = (Context) session.getAttribute(CONTEXT);  
		if (ctx != null) {
			session.removeAttribute(CONTEXT);
		}
	}

}
